=begin pod

=TITLE class Bag

=SUBTITLE Immutable collection of distinct objects with integer weights

    class Bag does Baggy { }

A C<Bag> is an immutable bag/multiset implementing
L<Associative|/type/Associative>, meaning a collection of distinct elements in
no particular order that each have an integer weight assigned to them
signifying how many copies of that element are considered "in the bag".  (For
I<mutable> bags, see L<BagHash> instead.)

C<Bag>s are often used for performing weighted random selections - see
L<.pick|pick> and L<.roll|roll>.

Objects/values of any type are allowed as bag elements.  Within a C<Bag>, items
that would compare positively with the L<===> operator are considered the same
element, with the number of how many there are as its weight.  But of course
you can also easily get back the expanded list of items (without the order):

=begin code
my $breakfast = bag <spam eggs spam spam bacon spam>;

say $breakfast.elems;      # OUTPUT: «3␤»
say $breakfast.keys.sort;  # OUTPUT: «bacon eggs spam␤»

say $breakfast.total;      # OUTPUT: «6␤»
say $breakfast.kxxv.sort;  # OUTPUT: «bacon eggs spam spam spam spam␤»
=end code

C<Bag>s can be treated as object hashes using the C<{ }> postcircumfix operator,
or the C< < > > operator for literal string keys, which returns the
corresponding integer weight for keys that are elements of the bag, and C<0> for
keys that aren't:

    my $breakfast = bag <spam eggs spam spam bacon spam>;
    say $breakfast<bacon>;    # OUTPUT: «1␤»
    say $breakfast<spam>;     # OUTPUT: «4␤»
    say $breakfast<sausage>;  # OUTPUT: «0␤»

=head1 Creating C<Bag> objects

C<Bag>s can be composed using the L<bag|#sub bag> subroutine (or C<Bag.new>, for
which it is a shorthand).  Any positional parameters, regardless of their type,
become elements of the bag:

    my $n = bag "a" => 0, "b" => 1, "c" => 2, "c" => 2;
    say $n.keys.perl;        # OUTPUT: «(:c(2), :b(1), :a(0)).Seq␤»
    say $n.keys.map(&WHAT);  # OUTPUT: «((Pair) (Pair) (Pair))␤»
    say $n.values.perl;      # OUTPUT: «(2, 1, 1).Seq␤»

Alternatively, the C<.Bag> coercer (or its functional form, C<Bag()>) can be
called on an existing object to coerce it to a C<Bag>.  Its semantics depend on
the type and contents of the object.  In general it evaluates the object in list
context and creates a bag with the resulting items as elements, although for
Hash-like objects or Pair items, only the keys become elements of the bag, and
the (cumulative) values become the associated integer weights:

    my $n = ("a" => 0, "b" => 1, "c" => 2, "c" => 2).Bag;
    say $n.keys.perl;        # OUTPUT: «("b", "c").Seq␤»
    say $n.keys.map(&WHAT);  # OUTPUT: «((Str) (Str))␤»
    say $n.values.perl;      # OUTPUT: «(1, 4).Seq␤»

Furthermore, you can get a C<Bag> by using bag operators (see next section) on
objects of other types such as L<List>, which will internally call C<.Bag>
on them before performing the operation.  Be aware of the tight precedence of
those operators though, which may require you to use parentheses around arguments:

    say (1..5) (+) 4;  # OUTPUT: «bag(1, 2, 3, 4(2), 5)␤»

=head1 Operators

Perl 6 provides common set and bag operators, which can take C<Bag>s (or any
other collections) as input, and return result as C<Bool>, C<Set> or C<Bag>
values.  For example:

=begin code
my ($a, $b) = bag(2, 2, 4), bag(2, 3, 3, 4);

say $a (<) $b;   # OUTPUT: «False␤»
say $a (<+) $b;  # OUTPUT: «False␤»
say $a (^) $b;   # OUTPUT: «bag(3(2), 2)␤»
say $a (+) $b;   # OUTPUT: «bag(2(3), 4(2), 3(2))␤»

# Unicode versions:
say $a ⊂ $b;  # OUTPUT: «False␤»
say $a ≼ $b;  # OUTPUT: «False␤»
say $a ⊖ $b;  # OUTPUT: «bag(3(2), 2)␤»
say $a ⊎ $b;  # OUTPUT: «bag(2(3), 4(2), 3(2))␤»
=end code

See L<Set/Bag Operators|/language/setbagmix#Set/Bag_Operators> for a complete list of set and bag operators
with detailed explanations.

=head1 Subroutines

=head2 sub bag

    sub bag(*@args --> Bag)

Creates a new C<Bag> from C<@args>.

=head1 See Also

L<Sets, Bags, and Mixes|/language/setbagmix>

=end pod

# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6
